package jp.co.nes.awssupport.tools.client;

import java.io.IOException;
import java.security.spec.InvalidKeySpecException;
import java.time.ZonedDateTime;
import java.util.Date;

import org.apache.commons.lang3.StringUtils;
import org.kohsuke.args4j.Option;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import jp.co.nes.awssupport.common.base.AbstractClient;
import jp.co.nes.awssupport.common.base.CommonException;
import jp.co.nes.awssupport.common.utility.AwsCloudFrontHelper;
import jp.co.nes.awssupport.common.utility.DateUtil;
import jp.co.nes.awssupport.common.utility.PropertiesUtil;

/**
 * CloudFrontを使用して、認証URLを標準出力します。<br>
 * <br>
 * 【クラスパスの設定】
 * awssupport-tools-X.X.X.jar(X.X.Xはバージョン)を設定します。<br>
 * また、log4jの設定ファイルであるlog4j.xmlを、クラスパスのルートに配置する必要があります。<br>
 * <br>
 * 【コマンドライン引数の内容】<br>
 * -o (--objectKey)・・左記オプションに続けて、半角スペース + 公開するファイルのs3オブジェクトキーの文字列を設定(必須)<br>
 * -e (--expirationValue)・・左記オプションに続けて、半角スペース + 有効期限(設定形式：uuuuMMddhhmmssSSS)(必須)<br>
 * <br>
 * 【プロパティの内容(※1)】<br>
 * CloudFrontProtocol・・CloudFront通信プロトコル(HTTP,HTTPS,RTMP)を設定(省略可、省略した場合は「HTTPS」)<br>
 * CloudFrontDomainName・・CloudFrontドメイン名を設定(必須)<br>
 * CloudFrontKeyPairPrivateKeyFileName・・CloudFrontキーペアprivateファイル名をフルパスで設定(必須)<br>
 * CloudFrontKeyPairId・・CloudFrontキーペアIDを設定(必須)<br>
 * CloudFrontUrlEncodeCharset・・url変換文字列(省略可、省略した場合は「UTF-8」)<br>
 * <br>
 * (※1) システムプロパティ or プロパティファイルで設定。両方に設定されていた場合、システムプロパティの内容が優先されます。<br>
 * <br>
 * 【タイムゾーンの設定】<br>
 * タイムゾーンの設定をシステムプロパティに実施する必要があります(-Duser.timezone=UTC)。<br>
 * <br>
 * 【その他】<br>
 * プロパティファイルの仕様・設定については、{@link PropertiesUtil}を参照。
 */
public class GenerateSignedUrlClient extends AbstractClient {

    /** ロガー */
    private static Logger logger = LoggerFactory.getLogger(GenerateSignedUrlClient.class);

    /** 公開するファイルのs3オブジェクトキー(コマンドライン引数で設定) */
    @Option(name = "-o", aliases = "--objectKey", usage = "公開するファイルのs3オブジェクトキー", metaVar = "objectKey", required = true)
    private String objectKey;

    /** 有効期限(設定形式：uuuuMMddhhmmssSSS)(コマンドライン引数で設定) */
    @Option(name = "-e", aliases = "--expirationValue", usage = "有効期限", metaVar = "expirationValue", required = true)
    private String expirationValue;

    /**
     * メインメソッドです。
     *
     * @param args コマンドライン引数
     */
    public static void main(String[] args) {
        GenerateSignedUrlClient client = new GenerateSignedUrlClient();
        client.execute(args);
    }

    /**
     * デフォルトコンストラクタです。
     */
    public GenerateSignedUrlClient() {
    }

    /*
     * (非 Javadoc)
     * @see jp.co.nes.awssupport.common.base.AbstractClient#execute()
     */
    @Override
    protected void execute() {
        if (expirationValue.length() != 17) {
            throw new CommonException("expirationValue is length wrong");
        }

        int year = Integer.parseInt(expirationValue.substring(0, 4));
        int month = Integer.parseInt(expirationValue.substring(4, 6));
        int day = Integer.parseInt(expirationValue.substring(6, 8));
        int hour = Integer.parseInt(expirationValue.substring(8, 10));
        int minute = Integer.parseInt(expirationValue.substring(10, 12));
        int second = Integer.parseInt(expirationValue.substring(12, 14));
        int nanoOfSecond = Integer.parseInt(expirationValue.substring(14));
        ZonedDateTime zdt = DateUtil.toZonedDateTime(year, month, day, hour, minute, second, nanoOfSecond);
        Date expirationDate = DateUtil.toDate(zdt);

        String protocol = PropertiesUtil.getProperty("CloudFrontProtocol", "HTTPS");

        String domainName = PropertiesUtil.getProperty("CloudFrontDomainName", "HTTPS");
        if (StringUtils.isEmpty(domainName)) {
            throw new CommonException("domainName is null or empty");
        }

        String keyPairPrivateKeyFilePath = PropertiesUtil.getProperty("CloudFrontKeyPairPrivateKeyFileName");
        if (StringUtils.isEmpty(keyPairPrivateKeyFilePath)) {
            throw new CommonException("keyPairPrivateKeyFilePath is null or empty");
        }

        String keyPairId = PropertiesUtil.getProperty("CloudFrontKeyPairId");
        if (StringUtils.isEmpty(keyPairId)) {
            throw new CommonException("keyPairId is null or empty");
        }

        String charSet = PropertiesUtil.getProperty("CloudFrontUrlEncodeCharset", "UTF-8");

        AwsCloudFrontHelper helper = new AwsCloudFrontHelper();
        try {
            String url = helper.generateSignedURL(protocol, domainName, keyPairPrivateKeyFilePath, objectKey, keyPairId,
                    expirationDate, charSet);
            System.out.println("url=" + url);
        } catch (InvalidKeySpecException | IOException e) {
            throw new CommonException(e);
        }
    }

    /*
     * (非 Javadoc)
     * @see jp.co.nes.awssupport.common.base.AbstractClient#finish(boolean, java.lang.Throwable)
     */
    @Override
    protected void finish(boolean isSuccess, Throwable throwable) {
        // 特に実装する内容無し
    }

    /*
     * (非 Javadoc)
     * @see jp.co.nes.awssupport.common.base.AbstractClient#debugArgument()
     */
    @Override
    protected void debugArgument() {
        if (logger.isDebugEnabled()) {
            logger.debug("objectKey=" + objectKey);
            logger.debug("expirationValue=" + expirationValue);
        }
    }
}
